// TypeScript中的枚举数类之数字枚举

// 使用枚举我们可以定义一些带名字的常量
// 使用枚举可以清晰的表达意图或创建一组由区别的用例
// Tytpescript支持数字的和基于字符串的枚举
// 创造枚举类型的值的关键字是enum

enum Direction{
    UP = '0',
    DOWN = '11',
    LEFT = 99,
    RIGHT
}
// console.log(Direction);

// 如上, 我们定义了一个数字枚举
// UP使用初始化为1(这个也被称为初始化器)
// 其他成员会从1开始自动增长
// 换句话说,Direction
// UP的值为1
// DOWN为2
// LEFT为3
// RIGHT为4

enum Direction2{
    UP,
    DOWN,
    LEFT,
    RIGHT
}
// 我们还可以完全使用初始化器:
// up的值为0
// DOWN的值的自增长的行为是很有用处的
// 但是要注意每个枚举材料员的值是不同的

// 枚举类型response的最终值
// 本质来讲,枚举类型是一个名值对,和值名对的结合体
// 可以铜通过值来访问键名,也可以通过键名访问值


// Typescript中的枚举类型之数字枚举
// 不带初始化器的枚举要么放在倒数第一的位置,
// 要么被放在使用了数字常量或其他常量初始化了的枚举后面

// Typescript中的枚举类型之字符串枚举
enum ldq{
    a="1",
    b=1
}
console.log(ldq);

// Typescript 众多的枚举数据类型之异构(Heterogeneou)枚举
// 从技术的角度来说, 枚举可以混合字符串和数字成员,
// 但是不太建议
enum BooleanLikeHeterogeneousEnum{
    No = 0,
    Yes = "Yes"
}
// Typrscript 中的枚举数据类型之计算成员
// 每个枚举成员都带有一个值,它可以是常量或计算出来的
// 当满足如下条件时,枚举成员被当作是常量
// 他是枚举的第一个成员且没有初始化器,这种情况下它被赋予值0
enum E{x}
console.log(E);
// 他不带有初始化器且它之前的枚举成员是一个数字常量
// 这种情况下,当前按枚举成员的值为它上一个枚举成员的值加一
enum E1 {x,y,z}
enum E2 {a=1,b,c}
console.log(E1);
console.log(E2);
// 枚举成员使用 常量枚举表达式初始化.
// 常量枚举表达式时Typescript表达式的子集
// 它可以在编译阶段求职
// 当表达式满足下面条件之一时
// 他就是一个常量枚举表达式
// (1).一个枚举表达式字面量(主要是字符串字面量或数字字面量)
// (2).一个对之前定义的常量枚举成员的引用(可以是在不同的枚举类型中定义的)
enum E3{x,y,z}
enum E4{A=E1.x,B,C}
// (3).带括号的常量表达式(表达式返回值是常量,但是这个初始化没法用函数的返回值)
// (4).一元运算符 +,-,~其中之一应用在了
// (5).常量枚举表达式作为二元1运算符 +, -, *, /, %, <<, >>>, &, |, ^的操作对象
// 若常数枚举表达式求值后为 NAN或 Infinity, 则会在编译阶段报错

// Typescript中的枚举数据类型值联合枚举
// 存在一种特殊的会计算的常量枚举成员的自己:字面量枚举成员,
// 字面量枚举长成员是指不带有初始值的常量枚举成员,或者是值被初始化为
    // 任何字符串字面量(例如:"foo","bar","baz")
    // 任何数字字面量(例如:1,100)
    // 应用了一元-符号的数字字面量(例如: -1, -100)

// 当所有枚举成员都拥有字面量枚举值时,它就带有了一种特殊的语义
// 首先,枚举成员成为了类型
// 例如,我们可以说某些成员 只能时枚举成员的值
enum ShapeKind{
    // 不带初始值的常量枚举,默认从0开始
    Circle,
    Square
}
interface Circle{
    kind:ShapeKind.Circle;
    radius:number;
}
interface Square{
    kind:ShapeKind.Square;
    sideLenght:number;
}
let c:Circle = {
    // kind:ShapeKind.Square,
    kind:ShapeKind.Circle,
    radius:100
}
enum E5 {x,y,z}
function f(obj:{x:number}){
    return obj.x;
}
// 这个是完全没有问题的,E里面就是有一个值为数字的x属性
f(E);
 
// typescript 中的枚举数据类型之反向映射
// 除了创建一个以属性名作为对象成员之外
// 数字枚举成员还具有了 反向映射, 从枚举值到枚举名字
// 即通过名称得道值,也可以通过值得到名称
enum Enum{
    A
}
let a = Enum.A;
let nameOfA = Enum[a];//"A"

// 生成的代码中, 枚举类型被编译成一个对象, 
// 它包含了正向映射(name->value)和方向映射(value->name)
// 引用枚举成员总会生成为对数学发个微博并且也不hi内联代码
// 要注意的是 不会为字符串枚举成员生成映射


// Typescript中的枚举数据类型值const枚举(常量枚举)

// 大多数情况下,枚举是十分有效的方案
// 然而在某些情况下需求分严格
// 为了避免在额外生成的代码是的1开心和额外的会直接的对枚举成员的访问,
// 我们可以使用const枚举
// 常量枚举通过在枚举上使用const修饰符来定义

// TS
const enum Enum2{
    A=1,
    B=A*2
}
// 编译后 JS 内容为空
// console.log(Enum2);

const enum Direction3{
    UP,DOWN,LEFT,RIGHT
}
let directions = [
    Direction3.UP,
    Direction3.DOWN,
    Direction3.LEFT,
    Direction3.RIGHT
];
console.log(...directions);
// 外部枚举
// 外部枚举用来描述已经存在的枚举类型的形状
declare enum Enum5{
    A=1,
    B,
    C=2
}
// 外部枚举和非外部枚举之间有一个重要的区别
// 在正常的枚举里,没有初始化方法的成员被当成常数成员
// 对于非常数的外部枚举而言,
// 没有初始化方法是被当作需要经过计算的


